package com.ocom.srvpaccess.controller;

import com.ocom.common.constant.SrvpAccessDeviceUrl;
import com.ocom.common.dto.MachInfoDto;
import com.ocom.common.dto.PerInfoDto;
import com.ocom.common.entity.access.*;
import com.ocom.common.entity.card.EntityCardInfo;
import com.ocom.common.entity.human.EntityDeptInfo;
import com.ocom.common.entity.human.EntityPersonnelInfo;
import com.ocom.common.enums.MachEnum;
import com.ocom.common.resp.RespMachMessage;
import com.ocom.common.utils.DateUtils;
import com.ocom.common.utils.RespUtilMach;
import com.ocom.common.vo.VerifyAccessVo;
import com.ocom.srvpaccess.service.*;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;



@Slf4j
@RestController
public class AccessController {
    Logger logger= LoggerFactory.getLogger(AccessController.class);

    @Autowired
    private MjDeviceInfoService deviceInfoService;

    @Autowired
    private PersonnelInfoService personnelInfoService;

    @Autowired
    private AreaInfoService areaInfoService;

    @Autowired
    private RegionInfoService regionInfoService;

    @Autowired
    private DeptInfoService deptInfoService;

    @Autowired
    private MjRecordService recordService;

    @Autowired
    private GroupPerService groupPerService;

    @Autowired
    private ZoneDateService zoneDateService;

    @Autowired
    private TimeInfoService timeInfoService;

    @Autowired
    XfCardInfoService xfCardInfoService;

    // 验证门禁权限（verifyAccess）
    @PostMapping(value = SrvpAccessDeviceUrl.URLP_ACCESSDEVICE_verifyAccess)
    public RespMachMessage verifyAccess(@Validated @RequestBody VerifyAccessVo verifyAccessVo){
        logger.info("验证门禁权限（verifyAccess） 参数 【{}】",verifyAccessVo);
        //判断参数
        if (verifyAccessVo.getCompanyId() <=0 ||
                verifyAccessVo.getMachNo() ==null||
                verifyAccessVo.getType() < 0 ||
                verifyAccessVo.getOperatetype() < 0 ||
                verifyAccessVo.getSerialnumber() == null  ||
                verifyAccessVo.getTime() == null){
            return RespUtilMach.error(MachEnum.PARAMS_ERROR);
        }
        Map<String, Object> map = new HashMap<>();
        //1、如果type=1（物理卡号），返回：
        //result=1（失败），msg=”系统不支持实体卡”， balckFlag=1（黑名单卡）
        if (verifyAccessVo.getType().equals(1)){

            /**
             * 根据卡号获取pid
             */
            EntityCardInfo entityCardInfo = xfCardInfoService.selectAccountNos(verifyAccessVo.getCompanyId(),verifyAccessVo.getIdnum());
            logger.info("验证门禁权限（verifyAccess） 卡信息 【{}】",entityCardInfo);
            if(entityCardInfo==null || entityCardInfo.getPId().equals(0l)){
                map.put("msg","卡不存在");
                map.put("balckFlag",1);
                map.put("permissionsFlag",1);
                map.put("idnum",0);
                map.put("overopentimes",0);
                map.put("overdueFlag",0);
                map.put("type",0);
                map.put("result",1);

                RespMachMessage respMachMessage=new RespMachMessage();
                respMachMessage.setCode("0001");
                respMachMessage.setMsg("卡不存在");
                respMachMessage.setData(map);
                return respMachMessage;
            }
            verifyAccessVo.setIdnum(entityCardInfo.getPId().toString());
        }
        //2、如果idnum为空字符串，返回：
        //result=1（失败），msg=”无人员信息”， balckFlag=1（黑名单卡）
        if (verifyAccessVo.getIdnum().isEmpty()){
            map.put("result",1);
            map.put("msg","无人员信息");
            map.put("balckFlag",1);
            map.put("permissionsFlag",1);
            map.put("idnum",0);
            map.put("overopentimes",0);
            map.put("overdueFlag",0);
            map.put("type",0);

            RespMachMessage respMachMessage2=new RespMachMessage();
            respMachMessage2.setCode("0001");
            respMachMessage2.setMsg("无人员信息");
            respMachMessage2.setData(map);
            return respMachMessage2;
        }
        //3、根据machNo从门禁设备表mj_device_info（连表门禁区域表mj_area_info、门禁片区表mj_region_info）
        // 查找 machID、machName、areaNo、areaName、regionID、regionName。
        MachInfoDto machInfoDto = deviceInfoService.selectmachNo(verifyAccessVo.getCompanyId(), verifyAccessVo.getMachNo());
        //如果查不到machID，返回：
        //result=1（失败），msg=”无设备信息”， permissionsFlag =1（无开门权限）
        if (machInfoDto == null || machInfoDto.getDeviceId() == null) {
            map.put("result", 1);
            map.put("msg", "无设备信息");
            map.put("permissionsFlag", 1);
            map.put("idnum", 0);
            map.put("balckFlag", 0);
            map.put("overopentimes", 0);
            map.put("overdueFlag", 0);
            map.put("type", 0);

            RespMachMessage respMachMessage3=new RespMachMessage();
            respMachMessage3.setCode("0003");
            respMachMessage3.setMsg("无设备信息");
            respMachMessage3.setData(map);
            return respMachMessage3;

        }
        //如果areaNo=0，返回：
        //result=1（失败），msg=”设备为备用机”， permissionsFlag =1（无开门权限）
        if (machInfoDto.getAreaId() == 0) {
            map.put("result", 1);
            map.put("msg", "设备为备用机");
            map.put("permissionsFlag", 1);
            map.put("idnum", 0);
            map.put("balckFlag", 0);
            map.put("overopentimes", 0);
            map.put("overdueFlag", 0);
            map.put("type", 0);
//            return RespUtilMach.success(map);

            RespMachMessage respMachMessage4=new RespMachMessage();
            respMachMessage4.setCode("0004");
            respMachMessage4.setMsg("设备为备用机");
            respMachMessage4.setData(map);
            return respMachMessage4;
        }

        //4、根据P_ID（idnum、userID）从人员信息表personnel_info（连表部门信息表dept_info）查找userName、userCode、deptID、deptName。
        //如果查不到userID，返回：
        //result=1（失败），msg=”无人员信息”， balckFlag=1（黑名单卡)
        PerInfoDto perInfoDto = personnelInfoService.selectPerInfo(verifyAccessVo.getCompanyId(), Long.valueOf(verifyAccessVo.getIdnum()));
        if (perInfoDto == null || perInfoDto.getPId() == null){
            map.put("result",1);
            map.put("msg","无人员信息");
            map.put("balckFlag",1);
            map.put("permissionsFlag",0);
            map.put("idnum",0);
            map.put("overopentimes",0);
            map.put("overdueFlag",0);
            map.put("type",0);

            RespMachMessage respMachMessage5=new RespMachMessage();
            respMachMessage5.setCode("0005");
            respMachMessage5.setMsg("无人员信息");
            respMachMessage5.setData(map);
            return respMachMessage5;
        }

        //5、调用3.1验证人员开门权限（参数：companyID，idnum，areaNo，Time）
        // 0返回：result=0（成功），msg=”允许开门”
        // 1,3返回：result=1（失败），msg=”无开门权限”， permissionsFlag =1（无开门权限）
        // 其它返回：result=1（失败），msg=”时区不存在”， permissionsFlag =1（无开门权限）

        int direction=verifyAccessVo.getDirection();
        if (verifyAccessVo.getDirection() !=1 && verifyAccessVo.getDirection() !=2){
            direction=machInfoDto.getOpenType();
        }
        Integer perOpenGroup = getPerOpenGroup(verifyAccessVo, machInfoDto,direction);
        if (perOpenGroup == 0){
            map.put("result",0);
            map.put("msg","允许开门");
            map.put("permissionsFlag",0);
            map.put("idnum",perInfoDto.getPId());
            map.put("balckFlag",0);
            map.put("overopentimes",0);
            map.put("overdueFlag",0);
            map.put("type",0);
            return RespUtilMach.success(map);
        }else if (perOpenGroup == 1 || perOpenGroup == 3){
            map.put("result",1);
            map.put("msg","无开门权限");
            map.put("permissionsFlag",1);
            map.put("idnum",perInfoDto.getPId());
            map.put("balckFlag",0);
            map.put("overopentimes",0);
            map.put("overdueFlag",0);
            map.put("type",0);

            RespMachMessage respMachMessage6=new RespMachMessage();
            respMachMessage6.setCode("0006");
            respMachMessage6.setMsg("无开门权限");
            respMachMessage6.setData(map);
            return respMachMessage6;
        }else {
            map.put("result",1);
            map.put("msg","时区不存在");
            map.put("permissionsFlag",1);
            map.put("idnum",perInfoDto.getPId());
            map.put("balckFlag",0);
            map.put("overopentimes",0);
            map.put("overdueFlag",0);
            map.put("type",0);

            RespMachMessage respMachMessage7=new RespMachMessage();
            respMachMessage7.setCode("0006");
            respMachMessage7.setMsg("时区不存在");
            respMachMessage7.setData(map);
            return respMachMessage7;
        }
    }

    private Integer getPerOpenGroup(VerifyAccessVo verifyAccessVo, MachInfoDto machInfoDto,Integer direction) {
        //1、判断人员在该区域的权限组。
        //从人员门禁权限表mj_group_per查找com_id= companyID、p_id= userID、area_id= areaNo的记录。
        EntityMjGroupPer entityMjGroupPer = groupPerService.selectGroupPer(verifyAccessVo.getCompanyId(), Long.valueOf(verifyAccessVo.getIdnum()), machInfoDto.getAreaId());
        //	如果记录存在，权限组 role_i = mj_group_per .group_no

        if (entityMjGroupPer==null){
            return 1;

        }
        Long groupNo = entityMjGroupPer.getGroupNo();
        //2、判断开门时间所属时区。
        //从 accessDateTime 截取日期（yyyy-MM-dd）accessDate，并计算是星期几（w）accessDay；
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        Date accessDate = null;
        try {
            accessDate = dateFormat.parse(String.valueOf(verifyAccessVo.getTime()));
        } catch (ParseException e) {
            e.printStackTrace();
        }

        Calendar cal = Calendar.getInstance(); // 获得一个日历
        cal.setTime(accessDate);
        Integer weekDayInt = cal.get(Calendar.DAY_OF_WEEK) - 1; // 指示一个星期中的某天。
        if (weekDayInt < 0)
            weekDayInt = 0;

        String weekDay  = weekDayInt.toString();
        //时区初始化 zoneNo = 0
        Long zoneNo = 0L;
        //先从门禁时区设置表mj_zone_date查找com_id= companyID、date_day= 0、date= accessDay的记录,
        Integer dateDay= 0;
        EntityMjZoneDate zoneDateInfo = zoneDateService.getZoneDateInfo(verifyAccessVo.getCompanyId(),dateDay, weekDay.toString());
        //	如果有记录：zoneNo = mj_zone_date . zone_no
        if (zoneDateInfo != null){
            zoneNo = zoneDateInfo.getZoneNo();
        }

        //再从门禁时区设置表mj_zone_date查找com_id= companyID、date_day= 1、date= accessDate的记录,
        dateDay=1;
        weekDay = verifyAccessVo.getTime().substring(0,10);
        EntityMjZoneDate dateInfo = zoneDateService.getZoneDateInfo(verifyAccessVo.getCompanyId(), dateDay, weekDay);
        //	如果有记录：zoneNo = mj_zone_date . zone_no
        if (dateInfo != null){
            zoneNo = dateInfo.getZoneNo();
        }
        //		如果 zoneNo == 0：返回2；
        if (zoneNo == 0){
            return 2;
        }

        //3、判断开门时间是否在开门时段内。
        //从accessDateTime截取时间（HH:mm）accessTime

        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("HH:mm");

        String accessTime = null;


        try {
            Date dateTime = DateUtils.dateTime(DateUtils.YYYY_MM_DD_HH_MM_SS, verifyAccessVo.getTime());
            accessTime = simpleDateFormat.format(dateTime);

        } catch (Exception e) {
            e.printStackTrace();
        }
        //		从门禁时段表mj_time_info查找满足以下条件的记录，按time_no正向排序
        //com_id= companyID、group_no = role_i、zone_no = zoneNo、area_id = ( role_i < 17 ? 0 : areaNo )

        List<EntityMjTimeInfo> entityMjTimeInfos = timeInfoService.selectTimeInfo(verifyAccessVo.getCompanyId(), groupNo, zoneNo, machInfoDto.getAreaId(),direction);
        //		如果不存在记录，返回3；
        if (entityMjTimeInfos.size()==0){
            return 3;
        }
        //		否则逐条记录检查accessTime是否在开门时段内（检查逻辑见注A），只要有一条记录满足条件，返回0；
        //如果mj_time_info.start_time 小于 mj_time_info.end_time，要满足条件：
        //					accessTime >= start_time  and  accessTime < end_time
        //否则，要满足条件：
        //					accessTime>= start_time  or  accessTime < end_time
        for (EntityMjTimeInfo entityMjTimeInfo: entityMjTimeInfos) {
            //String格式的数据转化成Date格式,Date格式转化成String格式
//            SimpleDateFormat formatter= new SimpleDateFormat("HH:mm");
            try {
                String startTime = entityMjTimeInfo.getBeginTime();//Date格式

                String endTime = entityMjTimeInfo.getEndTime();
                if(startTime.compareTo(endTime) < 0) {
                    if (accessTime != null && accessTime.compareTo(startTime) >= 0 && accessTime.compareTo(endTime) < 0) {
                        return 0;
                    }
                }else if (accessTime != null && accessTime.compareTo(startTime) >= 0 || accessTime != null && accessTime.compareTo(endTime) < 0){
                    return 0;
                }else {
                    return 3;
                }
            } catch (Exception e) {
                e.printStackTrace();
            }

        }
        //都不满足条件，返回3。
        return 3;
    }


    // 保存门禁记录（saveAccessRecord）
    @Deprecated
    @PostMapping(value = SrvpAccessDeviceUrl.URLP_ACCESSDEVICE_saveAccessRecord)
    public RespMachMessage saveAccessRecord(Long companyId,String machNo,Long idnum,String accessTime,Long accessMode){

        //1、根据machNo从门禁设备表mj_device_info查出machID、machName、areaNo；
        EntityMjDeviceInfo deviceInfo = deviceInfoService.getDeviceInfo(companyId, machNo);
        if (deviceInfo == null){
            logger.info("机器号为空");
            return RespUtilMach.error(MachEnum.AUTH_ERROR);
        }
        Long deviceId = deviceInfo.getDeviceId();
        String deviceName = deviceInfo.getDeviceName();
        Long areaId = deviceInfo.getAreaId();

        //2、根据areaNo从门禁区域表mj_area_info查出areaName、regionID；
        EntityMjAreaInfo areaInfo = areaInfoService.getAreaInfo(companyId, areaId);
        String areaName = null;
        Long regionId = null;
        if (areaInfo != null){
            areaName = areaInfo.getAreaName();
            regionId = areaInfo.getRegionId();
        }

        //3、根据regionID从门禁片区表mj_region_info查出regionName；
        String regionName = null;
        if (regionId >= 0){
            EntityMjRegionInfo entityMjRegionInfo = regionInfoService.GetRegionInfo(regionId, companyId);
            if (entityMjRegionInfo!= null){
                regionName = entityMjRegionInfo.getRegionName();
            }
        }




        //4、根据idnum从人员信息表personnel_info查出userName、deptID；
        EntityPersonnelInfo perInfo = personnelInfoService.getPerInfo(companyId, idnum);
        if (perInfo == null){
            logger.info("人员信息为空");
            return RespUtilMach.error(MachEnum.AUTH_ERROR);
        }
        String pCode = perInfo.getPCode();
        String pName = perInfo.getPName();
        long pId = perInfo.getPId();
        long deptId = perInfo.getDeptId();

        //5、根据deptID从部门信息表dept_info查出deptName;
        EntityDeptInfo deptInfo = deptInfoService.getDeptInfo(companyId, deptId);
        String deptName = null;
        if (deptInfo != null){
            deptName = deptInfo.getDeptName();
        }

        //6、门禁记录表mj_record表添加一条记录。
        EntityMjRecord entityMjRecord = new EntityMjRecord();
        //设置参数
        entityMjRecord.setComId(companyId);
        entityMjRecord.setDeptId(deptId);
        entityMjRecord.setDeptName(deptName);

        entityMjRecord.setPId(pId);
        entityMjRecord.setPCode(pCode);
        entityMjRecord.setPName(pName);

        entityMjRecord.setDeviceId(deviceId);
        entityMjRecord.setDeviceName(deviceName);
        entityMjRecord.setDeviceNo(machNo);

        entityMjRecord.setRegionId(regionId);
        entityMjRecord.setRegionName(regionName);

        entityMjRecord.setAreaId(areaId);
        entityMjRecord.setAreaName(areaName);
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date date = null;
        try {
            date = simpleDateFormat.parse(accessTime);
        } catch (ParseException e) {
            e.printStackTrace();
        }

        entityMjRecord.setOpenTime(date);
        entityMjRecord.setOpenMode(accessMode);
        entityMjRecord.setOpenState(0L);
        entityMjRecord.setCreateTime(new Date());
        recordService.insertInfo(entityMjRecord,companyId);

        return RespUtilMach.success();
    }

    @PostMapping(value = SrvpAccessDeviceUrl.URLP_ACCESSDEVICE_getRegionInfo)
    public RespMachMessage getRegionInfo(Long comId,Integer regionId,Integer deptId,String regionName){
        List<EntityMjRegionInfo> entityMjRegionInfoList = regionInfoService.selectGetRegionInfo(comId, regionId,deptId,regionName);
        return RespUtilMach.success(entityMjRegionInfoList);
    }


}
